#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
n8n工作流监控系统 - 核心监控脚本
功能：分析候选人聊天记录、计算业务指标、生成可视化报告
"""

import pymysql
import json
import re
import sys
import io
import logging
from datetime import datetime, timedelta
from collections import defaultdict
from typing import Dict, List, Tuple
from decimal import Decimal
import os

SKIP_STDOUT_RECONFIG = os.environ.get('SKIP_STDOUT_RECONFIG') == '1'

# 修复Windows控制台中文显示乱码问题
if sys.platform == 'win32' and not SKIP_STDOUT_RECONFIG:
    import io
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
    sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')
    try:
        os.system('chcp 65001 >nul 2>&1')
    except Exception:
        pass

# 配置logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler(),
        logging.FileHandler('logs/monitor.log', encoding='utf-8')
    ]
)
logger = logging.getLogger(__name__)

# 导入AI评估模块
from ai_evaluator import create_analyzer

# 导入配置
try:
    from config import DB_CONFIG, SENSITIVE_WORDS, SALARY_KEYWORDS, PHOTO_REQUEST_KEYWORDS, GREETING_KEYWORDS, MONITOR_CONFIG, OUTPUT_CONFIG, DEEPSEEK_API_KEY
except ImportError:
    print("[WARNING] 未找到config.py，使用默认配置")
    DB_CONFIG = {
        'host': 'localhost',
        'port': 3306,
        'user': 'root',
        'password': 'your_password',
        'database': 'your_database',
        'charset': 'utf8mb4'
    }
    SENSITIVE_WORDS = ['傻逼', 'SB', '草你妈']
    SALARY_KEYWORDS = ['工资', '薪资', '薪水', '月薪', '收入', '元', '钱']
    PHOTO_REQUEST_KEYWORDS = ['发照片', '要照片', '生活照', '自拍']
    MONITOR_CONFIG = {
        'reply_rate_days': 30,
        'content_analysis_days': 7,
        'workflow_error_days': 7,
        'daily_stats_days': 30,
    }
    OUTPUT_CONFIG = {
        'report_file': 'static/monitor_report.json',
        'verbose': True,
    }
    DEEPSEEK_API_KEY = 'sk-c4c1f1dee680477ea17a5315431d9a4d'


class N8nMonitor:
    """n8n工作流监控器"""
    
    def __init__(self, db_config: Dict, deepseek_api_key: str = None):
        """初始化监控器"""
        self.db_config = db_config
        self.conn = None
        self.cursor = None
        
        # 初始化AI评估器
        if deepseek_api_key:
            try:
                self.salary_analyzer = create_analyzer(deepseek_api_key)
                self.ai_enabled = True
                print("[INFO] AI评估功能已启用")
            except Exception as e:
                print(f"[WARNING] AI评估功能初始化失败: {e}")
                self.salary_analyzer = None
                self.ai_enabled = False
        else:
            self.salary_analyzer = None
            self.ai_enabled = False
            print("[INFO] AI评估功能未启用")
    
    @staticmethod
    def convert_decimal(obj):
        """转换Decimal类型为Python原生类型，用于JSON序列化"""
        if isinstance(obj, Decimal):
            return float(obj)
        elif isinstance(obj, dict):
            return {k: N8nMonitor.convert_decimal(v) for k, v in obj.items()}
        elif isinstance(obj, list):
            return [N8nMonitor.convert_decimal(i) for i in obj]
        return obj
        
    def connect_db(self):
        """连接数据库"""
        try:
            logger.info("=" * 100)
            logger.info("[数据库连接] 开始连接数据库...")
            logger.debug(f"[数据库连接] 数据库配置: host={self.db_config.get('host')}, port={self.db_config.get('port')}, user={self.db_config.get('user')}, database={self.db_config.get('database')}")
            
            self.conn = pymysql.connect(**self.db_config)
            self.cursor = self.conn.cursor(pymysql.cursors.DictCursor)
            
            logger.info("[数据库连接] 数据库连接成功")
            logger.debug(f"[数据库连接] 连接对象: {type(self.conn)}, 游标对象: {type(self.cursor)}")
            logger.info("=" * 100)
            
            print("[SUCCESS] 数据库连接成功")
            return True
        except pymysql.Error as e:
            logger.error(f"[数据库连接] MySQL错误: {type(e).__name__}: {str(e)}")
            logger.error(f"[数据库连接] 错误代码: {e.args[0] if len(e.args) > 0 else 'N/A'}")
            logger.error(f"[数据库连接] 错误消息: {e.args[1] if len(e.args) > 1 else 'N/A'}")
            logger.debug(f"[数据库连接] 完整错误堆栈:", exc_info=True)
            print(f"[ERROR] 数据库连接失败: {e}")
            return False
        except Exception as e:
            logger.error(f"[数据库连接] 未知错误: {type(e).__name__}: {str(e)}")
            logger.debug(f"[数据库连接] 完整错误堆栈:", exc_info=True)
            print(f"[ERROR] 数据库连接失败: {e}")
            return False
    
    def close_db(self):
        """关闭数据库连接"""
        if self.cursor:
            self.cursor.close()
        if self.conn:
            self.conn.close()
    
    # ========================================
    # 核心业务指标分析
    # ========================================
    
    def analyze_reply_rate(self, days: int = 30) -> Dict:
        """
        分析回流率：统计发送消息后，候选人是否回复
        
        候选人分类：
        1. 主动候选人：第一条消息是AI发送的（AI主动打招呼）
        2. 被动候选人：第一条消息是候选人发送的（候选人主动联系AI）
        
        回流定义：无论是哪种候选人，只要回复了AI发送的消息，都算回流
        
        返回三种回流率：
        1. 总回流率：所有候选人的回流情况
        2. 主动候选人回流率：主动候选人的回流情况
        3. 被动候选人回流率：被动候选人的回流情况
        """
        print(f"\n[ANALYZE] 分析最近 {days} 天的回流率...")
        
        # 查询最近N天的所有候选人
        query = """
        SELECT DISTINCT c.id, c.boss_uid, c.name, c.status
        FROM candidates c
        WHERE c.updated_at >= DATE_SUB(NOW(), INTERVAL %s DAY)
        """
        self.cursor.execute(query, (days,))
        candidates = self.cursor.fetchall()
        
        total_candidates = len(candidates)
        active_count = 0  # 主动候选人的数量（第一条消息是AI发送的）
        passive_count = 0  # 被动候选人的数量（第一条消息是候选人发送的）
        active_replied_count = 0  # 主动候选人中回流的数量
        passive_replied_count = 0  # 被动候选人中回流的数量
        total_replied_count = 0  # 总回流数量
        
        candidate_details = []
        
        for candidate in candidates:
            cid = candidate['id']
            
            # 获取该候选人的所有消息
            msg_query = """
            SELECT sender, content, created_at
            FROM messages
            WHERE candidate_id = %s
            ORDER BY created_at ASC
            """
            self.cursor.execute(msg_query, (cid,))
            messages = self.cursor.fetchall()
            
            if not messages:
                # 没有消息记录的候选人，归类为被动候选人且未回流
                passive_count += 1
                candidate_details.append({
                    'id': candidate['id'],
                    'name': candidate['name'],
                    'boss_uid': candidate['boss_uid'],
                    'status': candidate['status'],
                    'total_messages': 0,
                    'replied_back': False,
                    'is_active_candidate': False,
                    'chat_history': []
                })
                continue
            
            # 判断第一条消息的发送者，确定候选人类型
            first_message_sender = messages[0]['sender']
            is_active_candidate = (first_message_sender == '我')  # 第一条消息是AI发送的
            
            # 判断是否有AI发送的消息
            has_ai_message = any(msg['sender'] == '我' for msg in messages)
            
            # 判断候选人是否回复了AI的消息（回流判断）
            ai_sent = False
            candidate_replied_to_ai = False
            
            for msg in messages:
                if msg['sender'] == '我':
                    ai_sent = True
                elif ai_sent and msg['sender'] != '我':
                    candidate_replied_to_ai = True
                    break
            
            # 统计各类人数
            if is_active_candidate:
                active_count += 1
                if candidate_replied_to_ai:
                    active_replied_count += 1
                    total_replied_count += 1  # 主动候选人中回流的
            else:
                passive_count += 1
                if candidate_replied_to_ai:
                    passive_replied_count += 1
                    total_replied_count += 1  # 被动候选人中回流的
            
            # 格式化聊天记录，包含完整对话历史
            chat_messages = []
            for msg in messages:
                chat_messages.append({
                    'sender': msg['sender'],
                    'content': msg['content'],
                    'time': msg['created_at'].strftime('%Y-%m-%d %H:%M:%S') if msg['created_at'] and hasattr(msg['created_at'], 'strftime') else str(msg['created_at']) if msg['created_at'] else ''
                })
            
            # 添加所有有消息记录的候选人
            candidate_details.append({
                'id': candidate['id'],
                'name': candidate['name'],
                'boss_uid': candidate['boss_uid'],
                'status': candidate['status'],
                'total_messages': len(messages),
                'replied_back': candidate_replied_to_ai,
                'is_active_candidate': is_active_candidate,
                'chat_history': chat_messages
            })
        
        # 计算三种回流率
        total_reply_rate = (total_replied_count / total_candidates * 100) if total_candidates > 0 else 0
        active_reply_rate = (active_replied_count / active_count * 100) if active_count > 0 else 0
        passive_reply_rate = (passive_replied_count / passive_count * 100) if passive_count > 0 else 0
        
        result = {
            'total_candidates': total_candidates,
            'active_count': active_count,
            'passive_count': passive_count,
            'total_replied_count': total_replied_count,
            'active_replied_count': active_replied_count,
            'passive_replied_count': passive_replied_count,
            'total_reply_rate': round(total_reply_rate, 2),
            'active_reply_rate': round(active_reply_rate, 2),
            'passive_reply_rate': round(passive_reply_rate, 2),
            # 保持向后兼容
            'tracked_count': active_count,
            'untracked_count': passive_count,
            'tracked_replied_count': active_replied_count,
            'untracked_replied_count': passive_replied_count,
            'tracked_reply_rate': round(active_reply_rate, 2),
            'untracked_reply_rate': round(passive_reply_rate, 2),
            'reply_rate': round(active_reply_rate, 2),
            'replied_count': active_replied_count,
            'details': candidate_details
        }
        
        print(f"   总候选人数: {total_candidates}")
        print(f"   主动候选人数: {active_count}")
        print(f"   被动候选人数: {passive_count}")
        print(f"   总回流人数: {total_replied_count}")
        print(f"   主动回流人数: {active_replied_count}")
        print(f"   被动回流人数: {passive_replied_count}")
        print(f"   总回流率: {total_reply_rate:.2f}%")
        print(f"   主动回流率: {active_reply_rate:.2f}%")
        print(f"   被动回流率: {passive_reply_rate:.2f}%")
        
        return result
    
    def analyze_salary_with_ai(self, days: int = 7, test_mode: bool = False, test_limit: int = 5) -> Dict:
        """
        使用AI分析薪资信息（新方法）
        注意：为了确保有足够的数据，实际查询范围会使用reply_rate_days的时间范围
        
        Args:
            days: 查询天数
            test_mode: 测试模式，只处理限制数量的数据
            test_limit: 测试模式下的限制数量
        """
        print(f"\n[AI-ANALYZE] 使用AI分析薪资信息...")
        if test_mode:
            print(f"[AI-ANALYZE] 测试模式：只分析前 {test_limit} 条消息")
        
        if not self.ai_enabled:
            print("[ERROR] AI评估功能未启用，无法进行薪资分析")
            return {
                'total_candidates': 0,
                'total_messages': 0,
                'total_ai_messages': 0,
                'salary_related_messages': 0,
                'non_salary_related_messages': 0,
                'salary_rate': 0.0,
                'ai_analysis': {},
                'candidate_details': [],
                'all_salary_messages': [],
                'all_non_salary_messages': []
            }
        
        try:
            # 使用更大的时间范围确保能查到数据
            # 使用reply_rate_days作为查询范围，与回流率统计保持一致
            actual_days = MONITOR_CONFIG.get('reply_rate_days', 30)
            print(f"[INFO] 使用{actual_days}天的时间范围进行分析")
            
            # 获取所有候选人的聊天记录
            query = """
            SELECT DISTINCT c.id, c.name, c.boss_uid, c.status
            FROM candidates c
            WHERE c.updated_at >= DATE_SUB(NOW(), INTERVAL %s DAY)
            """
            self.cursor.execute(query, (actual_days,))
            candidates = self.cursor.fetchall()
            
            # 为每个候选人获取聊天记录
            candidates_data = []
            for candidate in candidates:
                cid = candidate['id']
                
                # 获取该候选人的所有消息
                msg_query = """
                SELECT sender, content, created_at
                FROM messages
                WHERE candidate_id = %s
                ORDER BY created_at ASC
                """
                self.cursor.execute(msg_query, (cid,))
                messages = self.cursor.fetchall()
                
                # 格式化聊天记录
                chat_messages = []
                for msg in messages:
                    chat_messages.append({
                        'id': len(chat_messages) + 1,
                        'sender': msg['sender'],
                        'content': msg['content'],
                        'created_at': msg['created_at'].strftime('%Y-%m-%d %H:%M:%S') if hasattr(msg['created_at'], 'strftime') else str(msg['created_at']) if msg['created_at'] else ''
                    })
                
                candidates_data.append({
                    'id': candidate['id'],
                    'name': candidate['name'],
                    'boss_uid': candidate['boss_uid'],
                    'status': candidate['status'],
                    'chat_history': chat_messages
                })
            
            # 测试模式限制数据量
            if test_mode and len(candidates_data) > test_limit:
                print(f"[AI-ANALYZE] 测试模式：限制候选人数量从 {len(candidates_data)} 到 {test_limit}")
                candidates_data = candidates_data[:test_limit]
            
            # 使用AI分析所有候选人
            ai_analysis = self.salary_analyzer.analyze_all_candidates(candidates_data, test_mode=test_mode, test_limit=test_limit if test_mode else None)
            
            # 格式化结果
            result = {
                'total_candidates': ai_analysis['total_candidates'],
                'total_messages': ai_analysis['total_messages'],
                'total_ai_messages': sum(1 for c in candidates_data for msg in c['chat_history'] if msg['sender'] == '我'),
                'salary_related_messages': ai_analysis['total_salary_messages'],
                'non_salary_related_messages': ai_analysis['total_non_salary_messages'],
                'salary_rate': ai_analysis['overall_salary_rate'],
                'ai_analysis': ai_analysis,
                'candidate_details': ai_analysis['candidate_analyses'],
                'all_salary_messages': ai_analysis['all_salary_messages'],
                'all_non_salary_messages': ai_analysis['all_non_salary_messages']
            }
            
            print(f"   总候选人数: {result['total_candidates']}")
            print(f"   总消息数: {result['total_messages']}")
            print(f"   AI消息数: {result['total_ai_messages']}")
            print(f"   薪资相关消息: {result['salary_related_messages']}")
            print(f"   薪资相关率: {result['salary_rate']:.2f}%")
            
            return result
            
        except Exception as e:
            print(f"[ERROR] AI薪资分析失败: {e}")
            return {
                'total_candidates': 0,
                'total_messages': 0,
                'total_ai_messages': 0,
                'salary_related_messages': 0,
                'non_salary_related_messages': 0,
                'salary_rate': 0.0,
                'ai_analysis': {},
                'candidate_details': [],
                'all_salary_messages': [],
                'all_non_salary_messages': [],
                'error': str(e)
            }
    
    def analyze_photo_requests(self, days: int = 7) -> Dict:
        """
        分析索要照片信息：检查AI回复中是否包含索要照片的内容
        注意：为了确保有足够的数据，使用reply_rate_days的时间范围
        """
        # 使用更大的时间范围确保能查到数据
        actual_days = MONITOR_CONFIG.get('reply_rate_days', 30)
        print(f"\n[PHOTO] 分析最近 {actual_days} 天的索要照片信息...")
        
        # 查询所有AI发送的消息
        query = """
        SELECT m.id, m.candidate_id, m.content, m.created_at, c.name as candidate_name
        FROM messages m
        JOIN candidates c ON m.candidate_id = c.id
        WHERE m.sender = '我' 
        AND m.created_at >= DATE_SUB(NOW(), INTERVAL %s DAY)
        ORDER BY m.created_at DESC
        """
        self.cursor.execute(query, (actual_days,))
        ai_messages = self.cursor.fetchall()
        
        total_ai_messages = len(ai_messages)
        photo_request_count = 0
        
        issues = []
        
        for msg in ai_messages:
            content = msg['content']
            
            # 检查是否包含索要照片信息
            has_photo_request = self._check_photo_request(content)
            if has_photo_request:
                photo_request_count += 1
                issues.append({
                    'type': 'photo_request',
                    'candidate_name': msg['candidate_name'],
                    'content': content[:100] + '...' if len(content) > 100 else content,
                    'created_at': msg['created_at'].strftime('%Y-%m-%d %H:%M:%S') if hasattr(msg['created_at'], 'strftime') else str(msg['created_at']) if hasattr(msg['created_at'], 'strftime') else str(msg['created_at'])
                })
        
        result = {
            'total_ai_messages': total_ai_messages,
            'photo_request_count': photo_request_count,
            'photo_request_rate': round(photo_request_count / total_ai_messages * 100, 2) if total_ai_messages > 0 else 0,
            'issues': issues
        }
        
        print(f"   总AI消息数: {total_ai_messages}")
        print(f"   包含索要照片信息: {photo_request_count} ({result['photo_request_rate']:.2f}%)")
        
        return result
    
    def analyze_workflow_errors(self, days: int = 7) -> Dict:
        """
        分析工作流错误情况（从workflow_logs表读取）
        如果表为空或不存在，返回默认数据
        """
        print(f"\n[ANALYZE] 分析最近 {days} 天的工作流错误...")
        
        try:
            query = """
            SELECT 
                execution_status,
                COUNT(*) as count,
                AVG(execution_time_ms) as avg_time,
                MAX(execution_time_ms) as max_time
            FROM workflow_logs
            WHERE created_at >= DATE_SUB(NOW(), INTERVAL %s DAY)
            GROUP BY execution_status
            """
            self.cursor.execute(query, (days,))
            results = self.cursor.fetchall()
            
            stats = {
                'success': 0,
                'error': 0,
                'timeout': 0,
                'avg_time_ms': 0,
                'max_time_ms': 0
            }
            
            for row in results:
                status = row['execution_status']
                stats[status] = row['count']
                if status == 'success':
                    stats['avg_time_ms'] = int(row['avg_time'] or 0)
                    stats['max_time_ms'] = int(row['max_time'] or 0)
            
            total = stats['success'] + stats['error'] + stats['timeout']
            stats['total_executions'] = total
            stats['success_rate'] = round(stats['success'] / total * 100, 2) if total > 0 else 100
            
            print(f"   总执行次数: {total}")
            print(f"   成功: {stats['success']}")
            print(f"   错误: {stats['error']}")
            print(f"   超时: {stats['timeout']}")
            print(f"   成功率: {stats['success_rate']}%")
            
            return stats
            
        except Exception as e:
            print(f"   [WARNING] 无法读取workflow_logs表（可能表不存在）: {e}")
            return {
                'total_executions': 0,
                'success': 0,
                'error': 0,
                'timeout': 0,
                'success_rate': 100,
                'avg_time_ms': 0,
                'max_time_ms': 0,
                'note': '需要在n8n工作流中添加日志记录节点'
            }
    
    def get_daily_stats(self, days: int = 30) -> List[Dict]:
        """
        获取每日统计数据（用于图表展示）
        """
        print(f"\n[STATS] 获取最近 {days} 天的每日统计...")
        
        daily_data = []
        
        for i in range(days - 1, -1, -1):
            target_date = datetime.now() - timedelta(days=i)
            date_str = target_date.strftime('%Y-%m-%d')
            
            # 查询当天的消息数
            query = """
            SELECT 
                COUNT(*) as total_messages,
                SUM(CASE WHEN sender = '我' THEN 1 ELSE 0 END) as ai_messages,
                SUM(CASE WHEN sender != '我' THEN 1 ELSE 0 END) as candidate_messages,
                COUNT(DISTINCT candidate_id) as active_candidates
            FROM messages
            WHERE DATE(created_at) = %s
            """
            self.cursor.execute(query, (date_str,))
            result = self.cursor.fetchone()
            
            daily_data.append({
                'date': date_str,
                'total_messages': result['total_messages'] or 0,
                'ai_messages': result['ai_messages'] or 0,
                'candidate_messages': result['candidate_messages'] or 0,
                'active_candidates': result['active_candidates'] or 0
            })
        
        return daily_data
    
    def get_enhanced_statistics(self, days: int = 30) -> Dict:
        """
        获取增强的统计数据，包括趋势分析、准确性验证等
        """
        print(f"\n[ENHANCED] 获取增强统计数据...")
        
        # 获取每日统计数据
        daily_stats = self.get_daily_stats(days)
        
        # 计算趋势分析
        if len(daily_stats) >= 7:
            recent_7_days = daily_stats[-7:]
            previous_7_days = daily_stats[-14:-7] if len(daily_stats) >= 14 else daily_stats[:-7]
            
            # 计算平均消息数趋势
            recent_avg = sum(d['total_messages'] for d in recent_7_days) / len(recent_7_days)
            previous_avg = sum(d['total_messages'] for d in previous_7_days) / len(previous_7_days) if previous_7_days else recent_avg
            
            message_trend = "increasing" if recent_avg > previous_avg else "decreasing" if recent_avg < previous_avg else "stable"
            message_growth_rate = ((recent_avg - previous_avg) / previous_avg * 100) if previous_avg > 0 else 0
            
            # 计算活跃候选人数趋势
            recent_active_avg = sum(d['active_candidates'] for d in recent_7_days) / len(recent_7_days)
            previous_active_avg = sum(d['active_candidates'] for d in previous_7_days) / len(previous_7_days) if previous_7_days else recent_active_avg
            
            active_trend = "increasing" if recent_active_avg > previous_active_avg else "decreasing" if recent_active_avg < previous_active_avg else "stable"
            active_growth_rate = ((recent_active_avg - previous_active_avg) / previous_active_avg * 100) if previous_active_avg > 0 else 0
        else:
            message_trend = "insufficient_data"
            message_growth_rate = 0
            active_trend = "insufficient_data"
            active_growth_rate = 0
        
        # 计算总体统计
        total_messages = sum(d['total_messages'] for d in daily_stats)
        total_ai_messages = sum(d['ai_messages'] for d in daily_stats)
        total_candidate_messages = sum(d['candidate_messages'] for d in daily_stats)
        avg_daily_messages = total_messages / len(daily_stats) if daily_stats else 0
        avg_daily_active = sum(d['active_candidates'] for d in daily_stats) / len(daily_stats) if daily_stats else 0
        
        # 计算消息分布
        ai_message_ratio = (total_ai_messages / total_messages * 100) if total_messages > 0 else 0
        candidate_message_ratio = (total_candidate_messages / total_messages * 100) if total_messages > 0 else 0
        
        # 数据质量检查
        data_quality_score = self._calculate_data_quality_score(daily_stats)
        
        enhanced_stats = {
            'period_days': days,
            'total_messages': total_messages,
            'total_ai_messages': total_ai_messages,
            'total_candidate_messages': total_candidate_messages,
            'avg_daily_messages': round(avg_daily_messages, 2),
            'avg_daily_active_candidates': round(avg_daily_active, 2),
            'ai_message_ratio': round(ai_message_ratio, 2),
            'candidate_message_ratio': round(candidate_message_ratio, 2),
            'message_trend': message_trend,
            'message_growth_rate': round(message_growth_rate, 2),
            'active_trend': active_trend,
            'active_growth_rate': round(active_growth_rate, 2),
            'data_quality_score': data_quality_score,
            'daily_breakdown': daily_stats
        }
        
        print(f"   总消息数: {total_messages}")
        print(f"   AI消息占比: {ai_message_ratio:.2f}%")
        print(f"   消息趋势: {message_trend} ({message_growth_rate:+.2f}%)")
        print(f"   数据质量评分: {data_quality_score}/100")
        
        return enhanced_stats
    
    def _calculate_data_quality_score(self, daily_stats: List[Dict]) -> int:
        """
        计算数据质量评分（0-100）
        """
        if not daily_stats:
            return 0
        
        score = 100
        
        # 检查数据完整性
        for stat in daily_stats:
            # 检查必需字段
            required_fields = ['total_messages', 'ai_messages', 'candidate_messages', 'active_candidates']
            for field in required_fields:
                if field not in stat or stat[field] is None:
                    score -= 10
            
            # 检查数据一致性
            if stat.get('total_messages', 0) != stat.get('ai_messages', 0) + stat.get('candidate_messages', 0):
                score -= 5
            
            # 检查异常值
            if stat.get('total_messages', 0) < 0:
                score -= 15
            if stat.get('active_candidates', 0) < 0:
                score -= 10
        
        # 检查数据连续性
        zero_days = sum(1 for stat in daily_stats if stat.get('total_messages', 0) == 0)
        if zero_days > len(daily_stats) * 0.5:  # 超过50%的天数为0
            score -= 20
        
        return max(0, min(100, score))
    
    # ========================================
    # 辅助方法
    # ========================================
    
    def _check_salary_info(self, text: str) -> bool:
        """检查文本是否包含薪资信息"""
        text_lower = text.lower()
        return any(keyword in text or keyword in text_lower for keyword in SALARY_KEYWORDS)
    
    def _check_sensitive_words(self, text: str) -> List[str]:
        """检查文本是否包含敏感词，返回检测到的敏感词列表"""
        detected = []
        text_lower = text.lower()
        
        for word in SENSITIVE_WORDS:
            if word in text or word.lower() in text_lower:
                detected.append(word)
        
        return detected
    
    def _check_photo_request(self, text: str) -> bool:
        """检查文本是否包含索要照片信息"""
        text_lower = text.lower()
        return any(keyword in text or keyword in text_lower for keyword in PHOTO_REQUEST_KEYWORDS)
    
    def _check_greeting_message(self, text: str) -> bool:
        """检查文本是否是打招呼消息（完全固定的格式）
        精确匹配以下两种格式之一：
        1. " 送达 您好吖，我们提供日结133元-299元工作岗位..."
        2. " 已读 您好吖，我们提供日结133元-299元工作岗位..."
        """
        # 定义固定的打招呼消息模板
        greeting_template_suffix = "您好吖，我们提供日结133元-299元工作岗位【首月收入6000-8000元，第二月8000-20000元】四个小时/天，接受无经验，无需面试，每天下播后→微信结算（无礼物收入也发同样133-299元/天，保底到账哈），收到回复1"
        
        # 检查是否以" 送达"或" 已读"开头
        if text.startswith(' 送达 ') or text.startswith(' 已读 '):
            # 移除开头的" 送达 "或" 已读 "
            text_without_prefix = text[4:]
            
            # 检查剩余部分是否与模板完全匹配
            if text_without_prefix == greeting_template_suffix:
                return True
        
        return False
    
    def analyze_greeting_messages(self, days: int = 30) -> Dict:
        """
        分析打招呼信息：统计主动打招呼的消息数量
        注意：为了确保有足够的数据，使用reply_rate_days的时间范围
        不使用AI评估，只用固定字符串匹配
        """
        # 使用更大的时间范围确保能查到数据
        actual_days = MONITOR_CONFIG.get('reply_rate_days', 30)
        logger.info(f"[GREETING] ========== 开始分析打招呼信息 ==========")
        logger.info(f"[GREETING] 使用时间范围: 最近 {actual_days} 天")
        logger.info(f"[GREETING] 不使用AI评估，仅使用固定字符串匹配")
        
        # 查询所有AI发送的消息
        logger.info(f"[GREETING] 查询数据库中AI发送的消息...")
        query = """
        SELECT m.id, m.candidate_id, m.content, m.created_at, c.name as candidate_name
        FROM messages m
        JOIN candidates c ON m.candidate_id = c.id
        WHERE m.sender = '我' 
        AND m.created_at >= DATE_SUB(NOW(), INTERVAL %s DAY)
        ORDER BY m.created_at DESC
        """
        self.cursor.execute(query, (actual_days,))
        ai_messages = self.cursor.fetchall()
        
        total_ai_messages = len(ai_messages)
        greeting_count = 0
        
        logger.info(f"[GREETING] 查询完成，共获取 {total_ai_messages} 条AI消息")
        
        issues = []
        
        logger.info(f"[GREETING] 开始逐条检查消息是否为打招呼消息（不使用AI）...")
        for idx, msg in enumerate(ai_messages, 1):
            content = msg['content']
            
            # 检查是否是打招呼消息（使用固定字符串匹配，不使用AI）
            is_greeting = self._check_greeting_message(content)
            
            if idx <= 5:  # 前5条打印详细调试信息
                logger.debug(f"[GREETING] 检查第 {idx} 条消息: {content[:50]}... -> {'是打招呼' if is_greeting else '不是打招呼'}")
            
            if is_greeting:
                greeting_count += 1
                if idx <= 10:  # 前10条打招呼消息打印详细信息
                    logger.info(f"[GREETING] 发现第 {greeting_count} 条打招呼消息，候选人: {msg['candidate_name']}")
                issues.append({
                    'type': 'greeting',
                    'candidate_id': msg['candidate_id'],
                    'candidate_name': msg['candidate_name'],
                    'content': content[:100] + '...' if len(content) > 100 else content,
                    'created_at': msg['created_at'].strftime('%Y-%m-%d %H:%M:%S') if hasattr(msg['created_at'], 'strftime') else str(msg['created_at'])
                })
        
        result = {
            'total_ai_messages': total_ai_messages,
            'greeting_count': greeting_count,
            'greeting_rate': round(greeting_count / total_ai_messages * 100, 2) if total_ai_messages > 0 else 0,
            'issues': issues
        }
        
        logger.info(f"[GREETING] ========== 打招呼信息统计完成 ==========")
        logger.info(f"[GREETING] 总AI消息数: {total_ai_messages}")
        logger.info(f"[GREETING] 打招呼消息数: {greeting_count}")
        logger.info(f"[GREETING] 打招呼率: {result['greeting_rate']:.2f}%")
        logger.info(f"[GREETING] 未使用AI评估，仅使用固定字符串匹配")
        
        return result
    
    def generate_detail_url(self, detail_type: str) -> str:
        """生成详情页URL"""
        return f"detail.html?type={detail_type}"
    
    def generate_access_url(self, port: int = 8000) -> str:
        """生成访问网址"""
        import socket
        try:
            # 获取本机IP地址
            hostname = socket.gethostname()
            local_ip = socket.gethostbyname(hostname)
            return f"http://{local_ip}:{port}/index.html"
        except:
            # 如果获取IP失败，使用localhost
            return f"http://localhost:{port}/index.html"
    
    def save_access_url(self, url_file: str = "access_url.txt"):
        """保存访问网址到文件"""
        url = self.generate_access_url()
        with open(url_file, 'w', encoding='utf-8') as f:
            f.write(f"监控系统访问地址：\n{url}\n\n")
            f.write(f"生成时间：{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
        print(f"[SUCCESS] 访问网址已保存到: {url_file}")
        print(f"[URL] 监控系统访问地址: {url}")
    
    def get_user_chat_records(self, candidate_id: int, limit: int = 100, message_type: str = None) -> Dict:
        """
        获取指定用户的聊天记录
        
        Args:
            candidate_id: 候选人ID
            limit: 限制返回消息数量
            message_type: 消息类型过滤 ('ai' 或 'candidate')
        
        Returns:
            包含候选人信息和聊天记录的字典
        """
        import logging
        logger = logging.getLogger(__name__)
        
        try:
            logger.info(f"[获取聊天记录] ========== 开始查询候选人 {candidate_id} 的聊天记录 ==========")
            
            with self.conn.cursor(pymysql.cursors.DictCursor) as cursor:
                # 获取候选人信息（只查询实际存在的字段）
                candidate_query = """
                SELECT id, name, boss_uid, updated_at
                FROM candidates 
                WHERE id = %s
                """
                logger.debug(f"[获取聊天记录] 执行候选人查询: {candidate_query} with id={candidate_id}")
                cursor.execute(candidate_query, (candidate_id,))
                candidate_result = cursor.fetchone()
                logger.debug(f"[获取聊天记录] 候选人查询结果: {candidate_result}")
                
                if not candidate_result:
                    logger.warning(f"[获取聊天记录] 候选人 {candidate_id} 不存在")
                    return {
                        'candidate': None,
                        'messages': [],
                        'total_messages': 0,
                        'ai_messages': 0,
                        'candidate_messages': 0,
                        'error': '用户不存在'
                    }
                
                logger.info(f"[获取聊天记录] 找到候选人: {candidate_result.get('name')}")
                
                # 构建消息查询
                message_query = """
                SELECT id, sender, content, created_at
                FROM messages 
                WHERE candidate_id = %s
                """
                params = [candidate_id]
                
                # 添加消息类型过滤
                if message_type == 'ai':
                    message_query += " AND sender = '我'"
                    logger.debug(f"[获取聊天记录] 过滤消息类型: AI消息")
                elif message_type == 'candidate':
                    message_query += " AND sender != '我'"
                    logger.debug(f"[获取聊天记录] 过滤消息类型: 候选人消息")
                
                message_query += " ORDER BY created_at ASC LIMIT %s"
                params.append(limit)
                
                logger.debug(f"[获取聊天记录] 执行消息查询，limit={limit}, type={message_type}")
                cursor.execute(message_query, params)
                messages = cursor.fetchall()
                logger.info(f"[获取聊天记录] 查询到 {len(messages)} 条消息")
                
                # 处理时间格式
                processed_messages = []
                ai_count = 0
                candidate_count = 0
                
                for msg in messages:
                    processed_msg = {
                        'id': msg['id'],
                        'sender': msg['sender'],
                        'content': msg['content'],
                        'created_at': msg['created_at'].strftime('%Y-%m-%d %H:%M:%S') if hasattr(msg['created_at'], 'strftime') else str(msg['created_at'])
                    }
                    processed_messages.append(processed_msg)
                    
                    # 统计消息类型
                    if msg['sender'] == '我':
                        ai_count += 1
                    else:
                        candidate_count += 1
                
                logger.info(f"[获取聊天记录] 消息统计: 总数={len(processed_messages)}, AI={ai_count}, 候选人={candidate_count}")
                
                # 处理候选人信息，将数据库字段映射到前端需要的字段
                candidate_info = {
                    'id': candidate_result['id'],
                    'name': candidate_result['name'],
                    'phone': candidate_result.get('boss_uid', '未提供'),  # 使用boss_uid作为联系方式
                    'email': '未提供',  # 数据库中没有email字段
                    'created_at': candidate_result['updated_at'].strftime('%Y-%m-%d %H:%M:%S') if hasattr(candidate_result.get('updated_at'), 'strftime') else '未知'
                }
                
                logger.info(f"[获取聊天记录] ========== 查询成功，返回数据 ==========")
                
                return {
                    'candidate': candidate_info,
                    'messages': processed_messages,
                    'total_messages': len(processed_messages),
                    'ai_messages': ai_count,
                    'candidate_messages': candidate_count
                }
                
        except Exception as e:
            logger.error(f"[获取聊天记录] 查询失败: {str(e)}", exc_info=True)
            return {
                'candidate': None,
                'messages': [],
                'total_messages': 0,
                'ai_messages': 0,
                'candidate_messages': 0,
                'error': str(e)
            }
    
    def generate_user_chat_url(self, candidate_id: int) -> str:
        """生成用户聊天记录URL"""
        return f"user_chat.html?candidate_id={candidate_id}"
    
    def get_user_ai_message_pairs(self, days: int = None, limit: int = 50, 
                                   start_date: str = None, end_date: str = None) -> List[Dict]:
        """
        获取用户-AI消息对，用于回复合理评估
        
        Args:
            days: 查询最近多少天（向后兼容参数，如果提供start_date/end_date则忽略此参数）
            limit: 限制返回的对数（0表示不限制）
            start_date: 开始日期字符串 'YYYY-MM-DD'（可选）
            end_date: 结束日期字符串 'YYYY-MM-DD'（可选）
            
        Returns:
            消息对列表，格式: [{
                'candidate_id': int,
                'candidate_name': str,
                'user_message': str,
                'ai_reply': str,
                'created_at': str,
                'pair_id': int
            }]
        """
        try:
            # 判断使用日期范围还是天数
            if start_date or end_date:
                logger.info(f"[消息对] 开始获取日期范围内的用户-AI消息对")
                logger.info(f"[消息对] 开始日期: {start_date or '不限制'}")
                logger.info(f"[消息对] 结束日期: {end_date or '不限制'}")
                logger.info(f"[消息对] 条数限制: {limit if limit > 0 else '不限制'}")
                
                # 查询在指定日期范围内有消息的候选人（通过JOIN messages表）
                query = """
                SELECT DISTINCT c.id, c.name 
                FROM candidates c
                INNER JOIN messages m ON c.id = m.candidate_id
                WHERE 1=1
                """
                params = []
                
                if start_date:
                    query += " AND m.created_at >= %s"
                    params.append(start_date)
                
                if end_date:
                    # 结束日期包含当天全部，所以要加一天
                    query += " AND m.created_at < DATE_ADD(%s, INTERVAL 1 DAY)"
                    params.append(end_date)
                
                logger.debug(f"[消息对] 候选人查询SQL: {query}")
                logger.debug(f"[消息对] 查询参数: {params}")
                
                self.cursor.execute(query, params)
                candidates = self.cursor.fetchall()
                logger.info(f"[消息对] 在指定日期范围内找到 {len(candidates)} 个候选人")
                
            else:
                # 向后兼容：使用days参数
                if days is None:
                    days = 30  # 默认值
                logger.info(f"[消息对] 开始获取最近 {days} 天的用户-AI消息对，限制: {limit}")
                
                # 查询候选人的所有消息
                query = """
                SELECT DISTINCT c.id, c.name
                FROM candidates c
                WHERE c.updated_at >= DATE_SUB(NOW(), INTERVAL %s DAY)
                """
                self.cursor.execute(query, (days,))
                candidates = self.cursor.fetchall()
            
            all_pairs = []
            total_candidates = len(candidates)
            
            for candidate in candidates:
                candidate_id = candidate['id']
                candidate_name = candidate['name']
                
                # 获取该候选人的所有消息（支持日期范围筛选）
                msg_query = "SELECT id, sender, content, created_at FROM messages WHERE candidate_id = %s"
                msg_params = [candidate_id]
                
                # 添加日期范围条件
                if start_date:
                    msg_query += " AND created_at >= %s"
                    msg_params.append(start_date)
                
                if end_date:
                    # 结束日期包含当天全部，所以要加一天
                    msg_query += " AND created_at < DATE_ADD(%s, INTERVAL 1 DAY)"
                    msg_params.append(end_date)
                
                msg_query += " ORDER BY created_at ASC"
                
                logger.debug(f"[消息对] 候选人 {candidate_name} (ID={candidate_id}) 消息查询SQL: {msg_query}")
                logger.debug(f"[消息对] 查询参数: {msg_params}")
                
                self.cursor.execute(msg_query, msg_params)
                messages = self.cursor.fetchall()
                
                logger.debug(f"[消息对] 候选人 {candidate_name} 获取到 {len(messages)} 条原始消息")
                
                # 过滤掉打招呼的固定语句
                filtered_messages = []
                greeting_patterns = [
                    "送达 您好吖",
                    "已读 您好吖",
                    "我们提供日结133元-299元工作岗位"
                ]
                
                for msg in messages:
                    content = msg['content']
                    # 过滤掉打招呼消息
                    if any(pattern in content for pattern in greeting_patterns):
                        continue
                    filtered_messages.append(msg)
                
                logger.debug(f"[消息对] 候选人 {candidate_name} 过滤后剩余 {len(filtered_messages)} 条消息")
                
                # 🔥 新逻辑：形成用户-AI消息对
                # 正确处理：在AI这次回复和上一次回复之间，用户发过的所有消息
                pairs_before = len(all_pairs)
                
                # 找到所有AI回复的索引位置
                ai_reply_indices = []
                for idx, msg in enumerate(filtered_messages):
                    if msg['sender'] == '我':
                        ai_reply_indices.append(idx)
                
                logger.debug(f"[消息对] 候选人 {candidate_name} 找到 {len(ai_reply_indices)} 条AI回复")
                
                # 对于每一条AI回复，提取它与上一条AI回复之间的所有用户消息
                for ai_idx_pos, ai_msg_idx in enumerate(ai_reply_indices):
                    ai_msg = filtered_messages[ai_msg_idx]
                    
                    # 确定用户消息的起始位置
                    if ai_idx_pos == 0:
                        # 第一条AI回复，用户消息从开头到AI回复之前
                        start_idx = 0
                    else:
                        # 不是第一条AI回复，用户消息从上一条AI回复之后到当前AI回复之前
                        prev_ai_msg_idx = ai_reply_indices[ai_idx_pos - 1]
                        start_idx = prev_ai_msg_idx + 1
                    
                    end_idx = ai_msg_idx
                    
                    # 提取这个范围内的所有用户消息
                    user_messages = []
                    for i in range(start_idx, end_idx):
                        msg = filtered_messages[i]
                        if msg['sender'] != '我':  # 用户消息
                            user_messages.append(msg['content'])
                    
                    # 如果有用户消息，形成一个消息对
                    if user_messages:
                        # 多条用户消息用分隔符连接
                        combined_user_message = '\n---\n'.join(user_messages)
                        
                        all_pairs.append({
                            'candidate_id': candidate_id,
                            'candidate_name': candidate_name,
                            'user_message': combined_user_message,
                            'user_message_count': len(user_messages),  # 新增：记录用户消息数量
                            'ai_reply': ai_msg['content'],
                            'created_at': str(filtered_messages[start_idx]['created_at']),  # 使用第一条用户消息的时间
                            'pair_id': len(all_pairs) + 1
                        })
                        
                        logger.debug(f"[消息对] 形成消息对: {len(user_messages)}条用户消息 -> 1条AI回复")
                    else:
                        logger.debug(f"[消息对] AI回复前没有用户消息，跳过 (AI消息索引={ai_msg_idx})")
                
                pairs_after = len(all_pairs)
                pairs_added = pairs_after - pairs_before
                logger.debug(f"[消息对] 候选人 {candidate_name} 形成了 {pairs_added} 对消息，当前总计 {pairs_after} 对")
                
                # 如果达到限制且不是0（0表示获取全部），停止
                if limit > 0 and len(all_pairs) >= limit:
                    logger.info(f"[消息对] 已获取 {limit} 对消息，停止处理")
                    break
            
            logger.info(f"[消息对] 共获取 {len(all_pairs)} 对消息")
            logger.info(f"[消息对] limit参数: {limit} (0=全部, 其他=限制)")
            
            # 如果limit为0，返回全部；否则返回限制数量
            if limit == 0:
                logger.info(f"[消息对] limit=0，返回全部 {len(all_pairs)} 对消息")
                return all_pairs
            else:
                result = all_pairs[:limit]  # 确保不超过限制
                logger.info(f"[消息对] limit={limit}，实际返回 {len(result)} 对消息")
                return result
            
        except Exception as e:
            logger.error(f"[消息对] 获取消息对失败: {str(e)}", exc_info=True)
            return []
    
    def get_message_dates(self) -> List[Dict]:
        """
        获取所有有AI消息的日期列表及每日AI消息数
        
        Returns:
            日期列表，格式: [{
                'date': 'YYYY-MM-DD',
                'pair_count': int  # 该日期的AI消息数（字段名保持pair_count以兼容前端）
            }]
        """
        try:
            logger.info("[消息日期] ========== 开始查询消息日期列表 ==========")
            
            # 查询所有有AI消息的日期及消息数
            # 注意：这里统计的是AI消息（sender='我'），用于AI信息统计页面
            query = """
            SELECT 
                DATE(created_at) as message_date,
                COUNT(*) as message_count
            FROM messages
            WHERE sender = '我'
            GROUP BY DATE(created_at)
            ORDER BY message_date DESC
            """
            
            logger.debug(f"[消息日期] 执行SQL查询: {query}")
            self.cursor.execute(query)
            results = self.cursor.fetchall()
            
            logger.info(f"[消息日期] 查询完成，共找到 {len(results)} 个日期")
            
            # 处理结果
            dates = []
            for row in results:
                date_str = row['message_date'].strftime('%Y-%m-%d') if hasattr(row['message_date'], 'strftime') else str(row['message_date'])
                message_count = row['message_count']
                
                # 返回AI消息数（字段名保持pair_count以兼容前端）
                pair_count = message_count
                
                dates.append({
                    'date': date_str,
                    'pair_count': pair_count
                })
                
                logger.debug(f"[消息日期] 日期: {date_str}, AI消息数: {pair_count}")
            
            logger.info(f"[消息日期] ========== 查询成功，返回 {len(dates)} 个日期 ==========")
            return dates
            
        except Exception as e:
            logger.error(f"[消息日期] 查询失败: {str(e)}", exc_info=True)
            return []
    
    # ========================================
    # 主执行方法
    # ========================================
    
    def generate_report(self, output_file: str = None):
        """
        生成完整的监控报告
        """
        if output_file is None:
            output_file = OUTPUT_CONFIG.get('report_file', 'static/monitor_report.json')
        
        print("=" * 60)
        print("[START] 开始生成n8n工作流监控报告")
        print("=" * 60)
        
        if not self.connect_db():
            return False
        
        try:
            # 1. 回流率分析
            logger.info("=" * 60)
            logger.info("[REPORT] 步骤 1/6: 开始回流率分析（不使用AI）")
            logger.info("=" * 60)
            reply_stats = self.analyze_reply_rate(days=MONITOR_CONFIG['reply_rate_days'])
            
            # 2. AI薪资分析（使用新的AI评估方法 - 这里会看到AI评估日志）
            logger.info("=" * 60)
            logger.info("[REPORT] 步骤 2/6: 开始AI薪资分析（使用AI评估）")
            logger.info("[REPORT] 注意：以下会看到'正在评估'和'[AI评估]'日志，这是正常的AI评估过程")
            logger.info("=" * 60)
            # 检查是否有--test参数
            import sys
            test_mode = '--test' in sys.argv
            test_limit = 5 if test_mode else None
            content_stats = self.analyze_salary_with_ai(days=MONITOR_CONFIG['content_analysis_days'], test_mode=test_mode, test_limit=test_limit)
            
            # 3. 索要照片信息分析
            logger.info("=" * 60)
            logger.info("[REPORT] 步骤 3/6: 开始索要照片信息分析（不使用AI）")
            logger.info("=" * 60)
            photo_stats = self.analyze_photo_requests(days=MONITOR_CONFIG['content_analysis_days'])
            
            # 3.1. 打招呼信息分析（不使用AI评估，仅字符串匹配）
            logger.info("=" * 60)
            logger.info("[REPORT] 步骤 4/6: 开始打招呼信息分析（不使用AI，仅字符串匹配）")
            logger.info("[REPORT] 注意：以下不会看到AI评估日志，只做固定字符串匹配")
            logger.info("=" * 60)
            greeting_stats = self.analyze_greeting_messages(days=MONITOR_CONFIG['content_analysis_days'])
            
            # 4. 工作流错误分析
            logger.info("=" * 60)
            logger.info("[REPORT] 步骤 5/6: 开始工作流错误分析")
            logger.info("=" * 60)
            error_stats = self.analyze_workflow_errors(days=MONITOR_CONFIG['workflow_error_days'])
            
            # 5. 每日统计数据
            daily_stats = self.get_daily_stats(days=MONITOR_CONFIG['daily_stats_days'])
            
            # 6. 增强统计数据
            enhanced_stats = self.get_enhanced_statistics(days=MONITOR_CONFIG['daily_stats_days'])
            
            # 汇总报告
            report = {
                'generated_at': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                'summary': {
                    'total_candidates': reply_stats['total_candidates'],
                    'active_candidates': reply_stats['active_count'],
                    'passive_candidates': reply_stats['passive_count'],
                    'total_replied_candidates': reply_stats['total_replied_count'],
                    'active_replied_candidates': reply_stats['active_replied_count'],
                    'passive_replied_candidates': reply_stats['passive_replied_count'],
                    'total_reply_rate': reply_stats['total_reply_rate'],
                    'active_reply_rate': reply_stats['active_reply_rate'],
                    'passive_reply_rate': reply_stats['passive_reply_rate'],
                    # 保持向后兼容
                    'tracked_candidates': reply_stats['tracked_count'],
                    'untracked_candidates': reply_stats['untracked_count'],
                    'tracked_replied_candidates': reply_stats['tracked_replied_count'],
                    'untracked_replied_candidates': reply_stats['untracked_replied_count'],
                    'tracked_reply_rate': reply_stats['tracked_reply_rate'],
                    'untracked_reply_rate': reply_stats['untracked_reply_rate'],
                    'replied_candidates': reply_stats['replied_count'],
                    'reply_rate': reply_stats['reply_rate'],
                    'total_ai_messages': content_stats['total_ai_messages'],
                    'salary_mentions': content_stats['salary_related_messages'],
                    'salary_rate': content_stats['salary_rate'],
                    'sensitive_issues': content_stats.get('sensitive_word_count', 0),
                    'photo_requests': photo_stats['photo_request_count'],
                    'greeting_messages': greeting_stats['greeting_count'],
                    'greeting_rate': greeting_stats['greeting_rate'],
                    'workflow_errors': error_stats['error'],
                    'workflow_success_rate': error_stats['success_rate']
                },
                'reply_rate_details': reply_stats,
                'content_analysis': content_stats,
                'ai_salary_analysis': content_stats.get('ai_analysis', {}),
                'photo_request_analysis': photo_stats,
                'greeting_analysis': greeting_stats,
                'workflow_performance': error_stats,
                'daily_statistics': daily_stats,
                'enhanced_statistics': enhanced_stats
            }
            
            # 转换Decimal类型并保存为JSON文件
            report = self.convert_decimal(report)
            with open(output_file, 'w', encoding='utf-8') as f:
                json.dump(report, f, ensure_ascii=False, indent=2)
            
            print("\n" + "=" * 60)
            print(f"[SUCCESS] 报告生成成功！已保存到: {output_file}")
            print("=" * 60)
            print(f"\n[STATS] 核心指标概览:")
            print(f"   - 总回流率: {reply_stats['total_reply_rate']:.2f}% ({reply_stats['total_replied_count']}/{reply_stats['total_candidates']})")
            print(f"   - 主动回流率: {reply_stats['active_reply_rate']:.2f}% ({reply_stats['active_replied_count']}/{reply_stats['active_count']})")
            print(f"   - 被动回流率: {reply_stats['passive_reply_rate']:.2f}% ({reply_stats['passive_replied_count']}/{reply_stats['passive_count']})")
            print(f"   - 薪资信息提及: {content_stats.get('salary_info_count', 0)} 次")
            print(f"   - 敏感词检测: {content_stats.get('sensitive_word_count', 0)} 次")
            print(f"   - 索要照片信息: {photo_stats['photo_request_count']} 次")
            print(f"   - 打招呼消息: {greeting_stats['greeting_count']} 次 ({greeting_stats['greeting_rate']:.2f}%)")
            print(f"   - 工作流成功率: {error_stats['success_rate']}%")
            
            return report
            
        except Exception as e:
            print(f"\n[ERROR] 生成报告时出错: {e}")
            import traceback
            traceback.print_exc()
            return False
        finally:
            self.close_db()


# ========================================
# 主程序入口
# ========================================

def main():
    """主函数"""
    print("\n" + "=" * 60)
    print("  n8n工作流监控系统 v1.0")
    print("=" * 60)
    
    # 创建监控器实例
    monitor = N8nMonitor(DB_CONFIG, DEEPSEEK_API_KEY)
    
    # 生成报告
    success = monitor.generate_report()
    
    if success:
        # 生成并保存访问网址
        monitor.save_access_url()
        print("\n[TIP] 提示: 请在浏览器中打开 index.html 查看可视化报告\n")
    else:
        print("\n[ERROR] 报告生成失败，请检查数据库配置和连接\n")


if __name__ == '__main__':
    main()

